#ifndef __MQ_EXCHANGE_HPP__
#define __MQ_EXCHANGE_HPP__

#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
#include <mutex>
#include <sstream>
#include "../mq_comm/mq_msg.pb.h"
#include "../mq_comm/helper.hpp"

namespace mq
{
    /*交换机类*/
    struct Exchange
    {
        using ptr = std::shared_ptr<Exchange>;
        std::string name;                                  // 交换机名称
        ExchangeType type;                                 // 交换机类型
        bool durable;                                      // 是否持久化
        bool auto_delete;                                  // 是否自动删除
        //std::unordered_map<std::string, std::string> args; // 其他参数
        google::protobuf::Map<std::string,std::string> args;

        Exchange() = default;
        Exchange(const std::string &_name, const ExchangeType &_type, bool _durable, bool _auto_delete,
                 const google::protobuf::Map<std::string,std::string>& _args)
            : name(_name), type(_type), durable(_durable), auto_delete(_auto_delete), args(_args)
        {
        }

        /*序列化其他参数，形如key=val&key=val&*/
        std::string getArgs()
        {
            std::stringstream ss;
            for(auto& iter:args)
            {
                ss<<iter.first<<"="<<iter.second<<"&";
            }
            return ss.str();
        }

        /*反序列化其他参数，将形如key=val&key=val&的字符串反序列化为args*/
        void setArgs(const std::string &str_args)
        {
            std::vector<std::string> vs;
            StrHelper::split(str_args,"&",&vs);
            for(auto& str:vs)
            {
                size_t pos=str.find("=");
                std::string key=str.substr(0,pos);
                std::string val=str.substr(pos+1);
                args[key]=val;
            }
        }
    };

    /*
        定义交换机数据操作类
        作用:主要是将通过数据库操作，将交换机的信息持久到数据库中
    */
    using ExchangeMap = std::unordered_map<std::string, Exchange::ptr>;
    class ExchangeMapper
    {
    public:
        ExchangeMapper(const std::string &filename) :_sql_helper(filename)
        {
            //考虑传递进来的filename是一个不存在的路径下的文件，所以首先是要先将他的父母了创建出来
            std::string parentPath=FileHelper::parentDirectory(filename);
            FileHelper::createDirectory(parentPath);
            assert(_sql_helper.open());
            createTable();
        }

        /*创建数据库表*/
        void createTable()
        {
            #define CREATE_EXCHANGE "create table if not exists exchange_table(\
                    name varchar(32) primary key,\
                    type int,\
                    durable int,\
                    auto_delete int,\
                    args varchar(128));"
            
            bool ret=_sql_helper.exec(CREATE_EXCHANGE,nullptr,nullptr);
            if(ret==false)
            {
                ELOG("创建交换机数据库表失败");
                abort();
            }
        }

        /*删除数据库表*/
        void removeTable()
        {
            #define DROP_EXCHANGE "drop table if exists exchange_table;"
            bool ret=_sql_helper.exec(DROP_EXCHANGE,nullptr,nullptr);
            if(ret==false)
            {
                ELOG("删除交换机数据库失败");
                abort();
            }
        }

        /*向数据库表中插入交换机信息*/
        bool insert(Exchange::ptr &exp)
        {
            std::stringstream ss;
            ss<<"insert into exchange_table values(";
            ss<<"'"<<exp->name<<"', ";
            ss<<exp->type<<", ";
            ss<<exp->durable<<", ";
            ss<<exp->auto_delete<<", ";
            ss<<"'"<<exp->getArgs()<<"');";
            return _sql_helper.exec(ss.str(),nullptr,nullptr);
        }

        /*根据交换机名称从数据库表中删除交换机信息*/
        void remove(const std::string &name)
        {
            std::stringstream ss;
            ss<<"delete from exchange_table where name=";
            ss<<"'"<<name<<"';";
            _sql_helper.exec(ss.str(),nullptr,nullptr);
        }

        /*从数据库中恢复所有交换机信息*/
        ExchangeMap recovery()
        {
            ExchangeMap result;
            std::string query="select name,type,durable,auto_delete,args from exchange_table;";
            _sql_helper.exec(query,selectCallback,&result);
            return result;
        }
    private:
        /*数据库执行的回调函数*/
        static int selectCallback(void* args, int col, char** rows, char** fields)
        {
            ExchangeMap* result=(ExchangeMap*)args;
            auto exp=std::make_shared<Exchange>();
            exp->name=rows[0];
            exp->type=(ExchangeType)std::stoi(rows[1]);
            exp->durable=(bool)std::stoi(rows[2]);
            exp->auto_delete=(bool)std::stoi(rows[3]);
            if(rows[4]) exp->setArgs(rows[4]);
            result->insert(std::make_pair(exp->name,exp));
            return 0;
        }


    private:
        SqliteHelper _sql_helper;
    };

    /*定义交换机管理类*/
    class ExchangeMannager
    {
    public:
        using ptr=std::shared_ptr<ExchangeMannager>;
        ExchangeMannager(const std::string &filename)
            :_mapper(filename)
        {
            _exchanges=_mapper.recovery();
        }

        /*声明交换机*/
        bool declareExchange(const std::string &name, const ExchangeType &type, bool durable, bool auto_delete,
                             const google::protobuf::Map<std::string,std::string>& args)
        {
            std::unique_lock<std::mutex> locK(_mutex);
            auto iter=_exchanges.find(name);
            if(iter!=_exchanges.end()) return true;//交换机已经存在,不需要声明
            auto exp=std::make_shared<Exchange>(name,type,durable,auto_delete,args);
            if(durable==true)
            {
                //需要持久化,存储一份到数据库表中
                bool ret=_mapper.insert(exp);
                if(ret==false) return false;
            }

            _exchanges.insert(std::make_pair(name,exp));
            return true;
        }

        /*指定交换机名称删除交换机*/
        void deleteExchange(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto iter=_exchanges.find(name);
            if(iter==_exchanges.end()) return;

            //删除要清理内存中的以及数据库表中的数据
            if(iter->second->durable==true) _mapper.remove(name);//只有将持久化标志为真的时候，才去数据库中删除
            _exchanges.erase(name);
            return;
        }

        /*根据交换机名称获取交换机信息*/
        Exchange::ptr selectExchange(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto iter=_exchanges.find(name);
            if(iter==_exchanges.end()) return Exchange::ptr();
            return iter->second;
        }

        /*根据交换机名称判断交换机是否存在*/
        bool exists(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto iter=_exchanges.find(name);
            if(iter==_exchanges.end()) return false;
            return true;
        }

        /*获取交换机数量*/
        size_t size()
        {
            std::unique_lock<std::mutex> locK(_mutex);
            return _exchanges.size();
        }

        /*清理所有交换机信息*/
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.removeTable();//删除表
            _exchanges.clear();//清理内存资源
        }

    private:
        std::mutex _mutex;      // 互斥锁
        ExchangeMapper _mapper; // 交换机数据操作类对象
        ExchangeMap _exchanges; //交换机哈希映射管理
    };
}

#endif